package com.tj.collection.utils;

import com.tj.collection.bean.AgentVo;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: sm
 * Date: 2019-08-26
 * Time: 20:15
 */
public class DispatchUtils {

    private static Integer DEFAULT_LIMIT = 100;

    private static Integer maxNum = 0;
    private static Integer totalOrderNums = 0;
    private static Integer dispatchedOrderNums = 0;

    private static Map<String, Integer> orders = new HashMap<>();
    private static List<AgentVo> agentVos = new ArrayList<>();
    private static List<String> singleLanguages = new ArrayList<>();


    public static void run(Map<String, Integer> ordersMap, List<AgentVo> agents) {
        //重置
        reset();

        orders = ordersMap;
        agentVos = agents;
        orders.values().forEach(v -> {
            totalOrderNums = totalOrderNums + v;
        });

        List<AgentVo> onlyOneLanguageAgent = findAgentsHaveOnlyOneLanguage(agentVos);
        List<AgentVo> languageHaveOneAgent = findLanguageHaveOneAgent(agentVos);

        one(null, languageHaveOneAgent);

        int maxLoopTimes = 1000;
        int lopTimes = 0;
        while (dispatchedOrderNums < totalOrderNums) {
            two();
            lopTimes++;
            if (lopTimes > maxLoopTimes) {
                break;
            }
        }
    }

    public static List<AgentVo> getAgentVos() {
        return agentVos;
    }


    private static void reset() {
        maxNum = 0;
        totalOrderNums = 0;
        dispatchedOrderNums = 0;
        orders = new HashMap<>();
        agentVos = new ArrayList<>();
        singleLanguages = new ArrayList<>();
    }

    /**
     * 把找到只负责单一语言的人 和找到一门语言只有一个人负责的那个人 先分配掉
     *
     * @param languageHaveOneAgent
     * @return
     */
    private static void one(List<AgentVo> onlyOneLanguageAgent, List<AgentVo> languageHaveOneAgent) {

        if (!CollectionUtils.isEmpty(onlyOneLanguageAgent)) {
            Map<String, Integer> sameLanguageAgentCountMap = new HashMap<>();
            onlyOneLanguageAgent.forEach(a -> {
                String languageName = a.getLanguageList().get(0);
                sameLanguageAgentCountMap.put(languageName, sameLanguageAgentCountMap.containsKey(languageName) ? sameLanguageAgentCountMap.get(languageName) + 1 : 1);
            });


            Map<String, Integer> dispatchNumMap = new HashMap<>();
            onlyOneLanguageAgent.forEach(a -> {
                String language = a.getLanguageList().get(0);

                Integer aveNum = dispatchNumMap.get(language);
                if (!dispatchNumMap.containsKey(language)) {
                    Integer agentNums = sameLanguageAgentCountMap.get(language);
                    Integer languageTotalOrderNum = orders.get(language);
                    if (languageTotalOrderNum == null) {
                        return;
                    }
                    aveNum = languageTotalOrderNum / agentNums;
                    dispatchNumMap.put(language, aveNum);
                }

                dispatch(orders, aveNum > DEFAULT_LIMIT ? DEFAULT_LIMIT : aveNum, a, null);
            });

        }

        if (!CollectionUtils.isEmpty(languageHaveOneAgent)) {
            languageHaveOneAgent.forEach(a -> {
                List<String> languageList = a.getLanguageList();
                List<String> singleLanguage = new ArrayList<>();
                languageList.forEach(l -> {
                    if (singleLanguages.contains(l)) {
                        singleLanguage.add(l);
                    }
                });

                dispatch(orders, 99999, a, singleLanguage);
            });
        }

    }


    private static void two() {
        List<AgentVo> availableAgents = new ArrayList<>();
        agentVos.forEach(a -> {
            if (!a.isFull()) {
                availableAgents.add(a);
                maxNum = a.getOrderNum() > maxNum ? a.getOrderNum() : maxNum;
            }
        });

        if (maxNum == 0) {
            maxNum = 10;
        }

        availableAgents.forEach(a -> {
            dispatch(orders, maxNum, a, null);
        });

        List<Integer> ordersNumList = new ArrayList<>();
        availableAgents.forEach(a -> {
            ordersNumList.add(a.getOrderNum());
        });


        int maxOrderNum = 0;
        for (int i = 0, size = ordersNumList.size(); i < size; i++) {
            Integer integer = ordersNumList.get(i);
            if (integer > maxOrderNum) {
                maxOrderNum = integer;
            }
        }

        maxNum = maxOrderNum + 10;

    }


    /**
     * 当前催收应该分单的最大值
     *
     * @param orders
     * @param maxOrderNums
     * @param agentVo
     */
    private static AgentVo dispatch(Map<String, Integer> orders, Integer maxOrderNums, AgentVo agentVo, List<String> singleLanguage) {
        if (agentVo.isFull()) {
            return agentVo;
        }

        if (agentVo.getOrderNum() >= maxOrderNums) {
            return agentVo;
        }

        Integer agentNeedOrdersNum = maxOrderNums - agentVo.getOrderNum();
        Integer languageNum = agentVo.getLanguageNum();


        Map<String, Integer> languageSupportNumMap = agentVo.getLanguageSupportNumMap();

        for (String l : agentVo.getLanguageList()) {
            if (!CollectionUtils.isEmpty(singleLanguage)) {
                if (!singleLanguage.contains(l)) {
                    continue;
                }
            }
            int aveNum = (int) Math.round(agentNeedOrdersNum / languageNum);

            Integer languageRemainOrderNum = orders.get(l);
            if (languageRemainOrderNum == null) {
                continue;
            }

            int updateNum = aveNum;
            if (languageRemainOrderNum < aveNum) {
                updateNum = languageRemainOrderNum;
            }
            orders.put(l, languageRemainOrderNum - updateNum);
            languageSupportNumMap.put(l, (languageSupportNumMap.containsKey(l) ? languageSupportNumMap.get(l) : 0) + updateNum);

            agentVo.setOrderNum(agentVo.getOrderNum() + updateNum);
            dispatchedOrderNums = dispatchedOrderNums + updateNum;

            languageNum--;
            agentNeedOrdersNum = agentNeedOrdersNum - updateNum;
        }

        if (agentVo.getOrderNum() >= agentVo.getMaxNum()) {
            agentVo.setFull(true);
        }

        return agentVo;

    }

    /**
     * 找到只负责单一语言的人
     *
     * @param agentVos
     */

    private static List<AgentVo> findAgentsHaveOnlyOneLanguage(List<AgentVo> agentVos) {

        List<AgentVo> oneLanguageAgentList = new ArrayList<>();
        agentVos.forEach(agentVo -> {
            if (agentVo.getLanguageNum() == 1) {
                oneLanguageAgentList.add(agentVo);
            }
        });

        return oneLanguageAgentList;
    }

    /**
     * 找到一门语言只有一个人负责的那个人
     *
     * @param agentVos
     * @return
     */
    private static List<AgentVo> findLanguageHaveOneAgent(List<AgentVo> agentVos) {


        Map<String, Integer> languageAndAgentNum = new HashMap<>();
        agentVos.forEach(a -> {
            List<String> languageList = a.getLanguageList();
            languageList.forEach(lan -> {
                if (languageAndAgentNum.containsKey(lan)) {
                    Integer newNum = languageAndAgentNum.get(lan) + 1;
                    languageAndAgentNum.put(lan, newNum);
                } else {
                    languageAndAgentNum.put(lan, 1);
                }
            });
        });

        //找到那些语言只有一个人负责
        languageAndAgentNum.forEach((lan, num) -> {
            if (num == 1) {
                singleLanguages.add(lan);
            }
        });

        List<AgentVo> languageHaveOneAgent = new ArrayList<>();
        agentVos.forEach(a -> {
            List<String> languageList = a.getLanguageList();
            languageList.forEach(ll -> {
                if (singleLanguages.contains(ll)) {
                    if (!languageHaveOneAgent.contains(a)) {
                        languageHaveOneAgent.add(a);
                    }
                }
            });
        });

        return languageHaveOneAgent;
    }

    public static void main(String[] args) {

        //输入一 ： 每种语言的订单数量
        Map<String, Integer> ordersMap = new HashMap<>();
        ordersMap.put("1", 130);
        ordersMap.put("2", 230);
        ordersMap.put("3", 320);
        ordersMap.put("4", 420);
        ordersMap.put("5", 620);

        //输入二 ： 每个催收会的语言
        AgentVo A = new AgentVo("A", "1", Arrays.asList("1", "2"), 510);
        AgentVo B = new AgentVo("B", "2", Arrays.asList("1", "2"), 520);
        AgentVo C = new AgentVo("C", "3", Arrays.asList("1"), 530);
        AgentVo D = new AgentVo("D", "4", Arrays.asList("3", "5"), 540);
        AgentVo E = new AgentVo("E", "5", Arrays.asList("4"), 550);
        AgentVo F = new AgentVo("F", "6", Arrays.asList("3", "5"), 560);

        List<AgentVo> agents = new ArrayList<>();
        agents.add(A);
        agents.add(B);
        agents.add(C);
        agents.add(D);
        agents.add(E);
        agents.add(F);

        run(ordersMap, agents);

        agentVos.forEach(a -> {
            String content = "催收人名：" + a.getName() + " 分单数：" + a.getOrderNum();

            Map<String, Integer> languageSupportNumMap = a.getLanguageSupportNumMap();
            for (String k : languageSupportNumMap.keySet()) {
                Integer value = languageSupportNumMap.get(k);
                content = content + " 语言：" + k + " 数量：" + value;
            }

            System.out.println(content);
        });
    }

}
